namespace SampleDbAccess
{
    using System;
    using SampleDbAccess.Model;
    using Stee.CAP8.DBAccess;
    using SampleDbAccess.Context;
    using System.Collections.Generic;
    using System.Linq.Expressions;
    using System.Threading.Tasks;

    internal class Program
    {
        private const string NewLine = "\r\n";
        public static void Main()
        {
            MainAsync().Wait();
            
        }
        public static async Task MainAsync()
        {
        }
        private static async Task AddSample()
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                var std = new Sample { Name = "Billy", Gender = "Male" };
                sRepo.Add(std);
                await unitOfWork.SaveChangesAsync();
                Console.Write("New sample record is added" + NewLine);
            }
        }

        private static async Task AddSampleWithConnectionStr()
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>(dbConStr: "Server=(local);Database=SampleDb2;Trusted_Connection=True;"))
            {
                var sRepo = new SampleRepository(unitOfWork);
                var std = new Sample { Name = "Billy", Gender = "Male" };
                sRepo.Add(std);
                await unitOfWork.SaveChangesAsync();
                Console.Write("New sample record is added" + NewLine);
            }
        }
        private static async Task AddRangeIEnumSample()
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                var std = new List<Sample>();
                for (var count = 1; count < 100; count++)
                {
                    if (count < 10)
                    {
                        std.Add(new Sample { Name = "0" + count.ToString(), Gender = "TRANSACTION TEST" });
                    }
                    else
                    {
                        std.Add(new Sample { Name = count.ToString(), Gender = "TRANSACTION TEST" });

                    }
                }
                sRepo.AddRange(std);
                await unitOfWork.SaveChangesAsync();
                Console.Write("Added new set: SUCCESS" + NewLine);
            }
        }
        private static async Task AddRangeParamTSample()
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                var std =
                    new Sample { Name = "ParamT1", Gender = "AddRange" };
                var std2 =
                    new Sample { Name = "ParamT2", Gender = "AddRange" };
                sRepo.AddRange(std, std2);
                await unitOfWork.SaveChangesAsync();

                Console.Write("New sample records is added by AddRangeParamT" + NewLine);
            }
        }
        private static async Task SingleSample(string id)
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                var result = await sRepo.GetSingleAsync(Guid.Parse(id));
                await unitOfWork.SaveChangesAsync();

                Console.Write("The Sample named " + result.Name + " is " + result.Gender + "." + NewLine);
            }
        }
        private static async Task SingleOrDefaultSample(string id)
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                
                var result = await sRepo.GetSingleOrDefaultAsync(Guid.Parse(id));
                await unitOfWork.SaveChangesAsync();

                var message = "There is no record found.";
                if (result != null)
                {
                    message = "The Sample named " + result.Name + " is " + result.Gender + ".";
                }
                Console.Write(message + NewLine);
            }
        }
        private static async Task UpdateSample(string id)
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                var result = sRepo.GetSingleOrDefault(Guid.Parse(id));
                if (result == null)
                {
                    throw new NullReferenceException();
                }
                result.Name += " (Updated)";
                sRepo.Update(result);
                await unitOfWork.SaveChangesAsync();

                var message = "There is no record found.";
                if (result != null)
                {
                    message = "The Sample named " + result.Name + " is updated.";
                }
                Console.Write(message + NewLine);
            }
        }
        private static async Task UpdatePropertySample(string id, string propertyName, string propertyValue)
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);

                sRepo.UpdateProperty(Guid.Parse(id), propertyName, propertyValue);
                await unitOfWork.SaveChangesAsync();

                Console.Write("Updated property by " + id + NewLine);
            }
        }
        private static async Task DeleteSample(string id = "")
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                var result = sRepo.GetSingleOrDefault(Guid.Parse(id));
                sRepo.Delete(result);
                await unitOfWork.SaveChangesAsync();

                Console.Write("Deleted record " + NewLine);
            }
        }
        private static async Task DeleteByIDSample(string id = "")
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                sRepo.DeleteByID(Guid.Parse(id));
                await unitOfWork.SaveChangesAsync();

                Console.Write("Deleted record by " + id + NewLine);
            }
        }
        private static async Task GetListSample(Expression<Func<Sample, bool>> condition = null, IList<OrderBy> orderBy = null)
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                var result = sRepo.GetList(condition, orderBy);
                await unitOfWork.SaveChangesAsync();

                foreach (var s in result)
                {
                    Console.Write(s.Name + NewLine);
                }
            }
        }

        private static async Task PaginationSample(Expression<Func<Sample, bool>> condition = null, IList<OrderBy> orderBy = null, int pageIndex = 1, int pageSize = 10000)
        {
            orderBy = new List<OrderBy>
            {
                new OrderBy { PropertyName = "Name" }
            };
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                var result = sRepo.GetList(condition, orderBy, pageIndex, pageSize);
                await unitOfWork.SaveChangesAsync();

                foreach (var s in result)
                {
                    Console.Write(s.Name + NewLine);
                }
            }
        }
        private static async Task RollbackSample()
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                unitOfWork.BeginTransaction();
                unitOfWork.BeginTransaction();
                try
                {
                    await GetListAndDeleteSample(sRepo, unitOfWork);
                    AddRangeIEnumAndExceptionSample(sRepo);
                    await unitOfWork.CommitTransactionAsync();
                }
                catch (Exception ex)
                {
                    Console.Write(ex.ToString() + NewLine);
                    Console.Write("Initializing rollback" + NewLine);
                    unitOfWork.RollbackTransaction();
                }
            }
        }
        private static async Task GetListAndDeleteSample(SampleRepository sRepo, UnitOfWork<SampleContext> unitOfWork)
        {
            var result = sRepo.GetList();
            foreach (var s in result)
            {
                sRepo.Delete(s);
            }
            await unitOfWork.SaveChangesAsync();
            Console.Write("Delete All: SUCCESS" + NewLine);
        }
        private static void AddRangeIEnumAndExceptionSample(SampleRepository sRepo)
        {
            var std = new List<Sample>();
            for (var count = 1; count < 15; count++)
            {
                if (count < 10)
                {
                    std.Add(new Sample { Name = "0" + count.ToString(), Gender = "TRANSACTION TEST" });
                }
                else
                {
                    std.Add(new Sample { Name = count.ToString(), Gender = "TRANSACTION TEST" });

                }
            }
            sRepo.AddRange(std);
            Console.Write("Added new set: FAILED" + NewLine);
            throw new Exception();
        }
        private static async Task TransactionSample()
        {
            using (var unitOfWork = new UnitOfWork<SampleContext>())
            {
                var sRepo = new SampleRepository(unitOfWork);
                unitOfWork.BeginTransaction();
                try
                {
                    AddRangeIEnumNoTransSample(sRepo);
                    AddRangeIEnumNoTransSample(sRepo);
                    await unitOfWork.CommitTransactionAsync();
                }
                catch(MultipleTransactionException ex)
                {
                    Console.Write(ex.ToString() + NewLine);
                }
                catch (Exception ex)
                {
                    Console.Write(ex.ToString() + NewLine);
                    Console.Write("Initializing rollback" + NewLine);
                    unitOfWork.RollbackTransaction();
                }
            }
        }
        private static void AddRangeIEnumNoTransSample(SampleRepository sRepo)
        {
            var std = new List<Sample>();
            for (var count = 1; count < 20; count++)
            {
                if (count < 10)
                {
                    std.Add(new Sample { Name = "0" + count.ToString(), Gender = "AddRangeIEnumNoTransSample TEST" });
                }
                else
                {
                    std.Add(new Sample { Name = count.ToString(), Gender = "AddRangeIEnumNoTransSample TEST" });

                }
            }
            sRepo.AddRange(std);
            Console.Write("Added new set: SUCCESS" + NewLine);
        }
    }
}
